#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>

#include <time.h>
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>

#include "../FIFO/fifo.h"
#include "../Carama/carama.h"
#include "../Socket/socket_thread.h"
#include "../LCD/lcd.h"
#include "../LED/led.h"

// 线程调度这一块还是有问题
#define SEND_PORI   15            // 比较吃资源的两个线程可以慢点
#define CTRL_PORI   15            // 比较吃资源的两个线程可以慢点
#define CARAMA_PORI 16            //
#define LCD_PORI    16            // 不卡
#define CONVERT_PROI 15          // 计算线程的优先级稍低

static pthread_t carama_tid;            // 捕捉caram图像的线程
static pthread_t send_tid;              // 发送图像的线程
static pthread_t ctrl_tid;              // 发送图像的线程
static pthread_t lcd_tid;               // 显示线程
static pthread_t convert_tid;           // 专门用来转换的线程
struct kfifo *global_carama_fifo;       //全局变量fifo
static int msg_key = -1;                //创建的消息队列的id(全局的)


void set_thread_priority(pthread_t thread, int priority) {
    struct sched_param param;
    param.sched_priority = priority;

    if (pthread_setschedparam(thread, SCHED_RR, &param) != 0) {
        perror("pthread_setschedparam");
        exit(EXIT_FAILURE);
    }
}
int main() {
    //signal(SIGPIPE, SIG_IGN); //别忽略到时候写个控制函数
    msg_key = msgget(12345, IPC_CREAT | 0666); // 创建消息队列
    if (msg_key == -1) {
        perror("msgget error");
        return -1;
    }

    led_init();
    printf("LED的亮度:%d\n", get_led_lightness(0));
    write_led_lightness(1, 255);
    printf("LED的亮度:%d\n", get_led_lightness(1));

    global_carama_fifo = kfifo_alloc(CARAMA_MAX_WIDTH, CARAMA_MAX_HEIGHT, FRAMEBUFFER_COUNT); // 创建fifo
    if (global_carama_fifo == NULL) {
        perror("global_carama_fifo error");
        msgctl(msg_key, IPC_RMID, NULL);
        return -1;
    }
    // 1.创建采集线程
    if(carama_init(CARAMA_PATH) == -1) {
        fprintf(stderr,"carama open error");
        return -1;
    }
    if (lcd_init(LCD_PATH) == -1) {
        fprintf(stderr, "LCD 初始化失败\n");
       return -1;
    }
    if (pthread_create(&carama_tid,NULL, carama_thread, &msg_key) != 0) {
        perror("pthread_create error");
        msgctl(msg_key, IPC_RMID, NULL);
        return -1;
    }
    set_thread_priority(carama_tid, CARAMA_PORI);
    // 2. 创建显示线程
    if (pthread_create(&lcd_tid,NULL, lcd_thread, &msg_key) != 0) {
        perror("pthread_create error");
        msgctl(msg_key, IPC_RMID, NULL);
        return -1;
    }
    set_thread_priority(lcd_tid, LCD_PORI);
    // 3. 创建格式转换线程
    if (pthread_create(&convert_tid,NULL, convert_thread, NULL) != 0) {
        perror("pthread_create error");
        msgctl(msg_key, IPC_RMID, NULL);
        return -1;
    }
    set_thread_priority(convert_tid, CONVERT_PROI);
    //3. 创建图传线程
    if((client_init(SERVER_ADDR,HOST,0)) == -1) {   // 先初始化图传
        fprintf(stderr,"img socket open error");
        return -1;
    }
    if (pthread_create(&send_tid,NULL, client_send_thread, NULL) != 0) {
        perror("pthread_create error");
        msgctl(msg_key, IPC_RMID, NULL);
        return -1;
    }
    set_thread_priority(send_tid, SEND_PORI);
    //4. 创建控制线程
    if((client_init(SERVER_ADDR,HOST,1)) == -1) {   // 在初始化控制(好吧这样写偷懒了不太好)
        fprintf(stderr,"control socket open error");
        return -1;
    }
    if (pthread_create(&ctrl_tid,NULL, client_control_thread, &msg_key) != 0) {
        perror("pthread_create error");
        msgctl(msg_key, IPC_RMID, NULL);
        return -1;
    }
    set_thread_priority(ctrl_tid, CTRL_PORI);

    // 等待线程结束
    pthread_join(send_tid, NULL);
    pthread_join(ctrl_tid, NULL);
    pthread_join(carama_tid, NULL);
    pthread_join(lcd_tid, NULL);
    pthread_join(convert_tid, NULL);
    // 释放资源
    kfifo_free(global_carama_fifo);
    msgctl(msg_key, IPC_RMID, NULL);
    
    return 0;
}